<?php
/**
 * Created by PhpStorm.
 * User: jksen
 * Date: 2018/1/30
 * Time: 上午10:12
 */

namespace app\common\ShaoHuoPay\Gateways;

use app\common\ShaoHuoPay\Contracts\GatewayApplicationInterface;
use app\common\ShaoHuoPay\Contracts\GatewayInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use app\common\ShaoHuoPay\Exceptions\GatewayException;
use app\common\ShaoHuoPay\Exceptions\InvalidSignException;
use app\common\ShaoHuoPay\Gateways\Alipay\AliTools;
use app\common\ShaoHuoPay\tools\Str;
use app\common\ShaoHuoPay\tools\ShCollection;


class Alipay implements GatewayApplicationInterface
{

    /**
     * @var
     */
    protected $config;

    /**
     * @var array
     */
    protected $payload;

    /**
     * @var string
     */
    protected $gateway;

    /**
     * 初始化配置
     * AliPay constructor.
     * @param $config
     */
    public function __construct($config)
    {
        $this->config = $config;
        $this->gateway = AliTools::baseUri($this->config->get('mode', 'normal'));
        $this->payload = [
            'app_id'      => $this->config->get('app_id'),
            'method'      => '',
            'format'      => 'JSON',
            'charset'     => 'utf-8',
            'sign_type'   => 'RSA2',
            'version'     => '1.0',
            'return_url'  => $this->config->get('return_url'),
            'notify_url'  => $this->config->get('notify_url'),
            'timestamp'   => date('Y-m-d H:i:s'),
            'sign'        => '',
            'biz_content' => '',
        ];
    }

    /**
     * 实现支付订单
     * @param $gateway
     * @param array $params
     * @return ShCollection|mixed|Response
     * @throws GatewayException
     */
    public function pay($gateway, $params = [])
    {
        $this->payload['biz_content'] = json_encode($params);

        $gateway = get_class($this).'\\'.Str::studly($gateway).'Gateway';

        if (class_exists($gateway)) {
            return $this->makePay($gateway);
        }

        throw new GatewayException("Pay Gateway [{$gateway}] not exists", 1);
    }

    /**
     * 验证签名
     * @return ShCollection|mixed
     * @throws InvalidSignException
     * @throws \App\common\ShaoHuoPay\Exceptions\InvalidConfigException
     */
    public function verify()
    {
        $request = Request::createFromGlobals();

        $data = $request->request->count() > 0 ? $request->request->all() : $request->query->all();

        $data = AliTools::encoding($data, 'utf-8', $data['charset'] ?? 'gb2312');

        //Log::debug('Receive Alipay Request:', $data);

        if (AliTools::verifySign($data, $this->config->get('ali_public_key'))) {
            return new ShCollection($data);
        }

        //Log::warning('Alipay Sign Verify FAILED', $data);

        throw new InvalidSignException('Alipay Sign Verify FAILED', 3, $data);
    }

    /**
     * 查询订单
     * @param $order
     * @return ShCollection
     * @throws GatewayException
     * @throws InvalidSignException
     * @throws \App\common\ShaoHuoPay\Exceptions\InvalidConfigException
     */
    public function find($order)
    {
        $this->payload['method'] = 'alipay.trade.query';
        $this->payload['biz_content'] = json_encode(is_array($order) ? $order : ['out_trade_no' => $order]);
        $this->payload['sign'] = AliTools::generateSign($this->payload, $this->config->get('private_key'));

        //Log::debug('Find An Order:', [$this->gateway, $this->payload]);

        return AliTools::requestApi($this->payload, $this->config->get('ali_public_key'));
    }

    /**
     * 退款
     * @param $order
     * @return ShCollection|mixed
     * @throws GatewayException
     * @throws InvalidSignException
     * @throws \App\common\ShaoHuoPay\Exceptions\InvalidConfigException
     */
    public function refund($order)
    {
        $this->payload['method'] = 'alipay.trade.refund';
        $this->payload['biz_content'] = json_encode($order);
        $this->payload['sign'] = AliTools::generateSign($this->payload, $this->config->get('private_key'));

        //Log::debug('Refund An Order:', [$this->gateway, $this->payload]);

        return AliTools::requestApi($this->payload, $this->config->get('ali_public_key'));
    }

    /**
     * 取消订单
     * @param $order
     * @return ShCollection
     * @throws GatewayException
     * @throws InvalidSignException
     * @throws \App\common\ShaoHuoPay\Exceptions\InvalidConfigException
     */
    public function cancel($order)
    {
        $this->payload['method'] = 'alipay.trade.cancel';
        $this->payload['biz_content'] = json_encode(is_array($order) ? $order : ['out_trade_no' => $order]);
        $this->payload['sign'] = AliTools::generateSign($this->payload, $this->config->get('private_key'));

        //Log::debug('Cancel An Order:', [$this->gateway, $this->payload]);

        return AliTools::requestApi($this->payload, $this->config->get('ali_public_key'));
    }

    /**
     * 关闭订单
     * @param $order
     * @return ShCollection
     * @throws GatewayException
     * @throws InvalidSignException
     * @throws \App\common\ShaoHuoPay\Exceptions\InvalidConfigException
     */
    public function close($order)
    {
        $this->payload['method'] = 'alipay.trade.close';
        $this->payload['biz_content'] = json_encode(is_array($order) ? $order : ['out_trade_no' => $order]);
        $this->payload['sign'] = AliTools::generateSign($this->payload, $this->config->get('private_key'));

        //Log::debug('Close An Order:', [$this->gateway, $this->payload]);

        return AliTools::requestApi($this->payload, $this->config->get('ali_public_key'));
    }

    /**
     * 校验成功返回成功信息
     * @return mixed|static
     */
    public function success()
    {
        return Response::create('success');
    }

    /**
     * 初始支付网关
     * @param $gateway
     * @return mixed
     * @throws GatewayException
     */
    protected function makePay($gateway)
    {
        $app = new $gateway($this->config);

        if ($app instanceof GatewayInterface) {
            return $app->pay($this->gateway, $this->payload);
        }

        throw new GatewayException("Pay Gateway [{$gateway}] Must Be An Instance Of GatewayInterface", 2);
    }

    /**
     * @param $method
     * @param $params
     * @return ShCollection|mixed|Response
     * @throws GatewayException
     */
    public function __call($method, $params)
    {
        return $this->pay($method, ...$params);
    }
}